package com.wtpaint.compiler.processor;

import com.google.auto.service.AutoService;
import com.wtpaint.annotation.Route;
import com.wtpaint.annotation.RouteMeta;
import com.wtpaint.annotation.RouteType;
import com.wtpaint.compiler.utils.Consts;
import com.wtpaint.compiler.utils.Log;
import com.wtpaint.compiler.utils.Utils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedOptions;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.Elements;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Types;

@AutoService(Process.class)
@SupportedOptions(Consts.ARGUMENTS_NAME)
@SupportedAnnotationTypes("com.wtpaint.annotation.Route")
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class RouteProcessor extends AbstractProcessor {

    private Map<String, String> rootMap = new TreeMap<>();

    private Map<String, List<RouteMeta>> groupMap = new TreeMap<>();

    private Elements elementUtils;

    private Types typesUtils;

    private String moudleName;

    private Log log;

    private Filer filerUtils;

    @Override
    public synchronized void init(ProcessingEnvironment processingEnvironment) {
        super.init(processingEnvironment);
        elementUtils = processingEnv.getElementUtils();
        filerUtils = processingEnv.getFiler();
        log = Log.newLog(processingEnvironment.getMessager());
        typesUtils = processingEnvironment.getTypeUtils();
        Map<String, String> options = processingEnv.getOptions();
        if (!Utils.isEmpty(options)) {
            moudleName = options.get(Consts.ARGUMENTS_NAME);
        }
        //仍然为空
        if (Utils.isEmpty(moudleName)) {
            throw new IllegalArgumentException("Not set Processor Parmaters.");
        }
    }

    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        if (!Utils.isEmpty(set)) {
            Set<? extends Element> routeElements = roundEnvironment.getElementsAnnotatedWith(Route.class);
            if (!Utils.isEmpty(routeElements)) {
                try {
                    parseRoutes(routeElements);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            return true;
        }
        return false;
    }

    private void parseRoutes(Set<? extends Element> routeElements) throws IOException {
        TypeElement activity = elementUtils.getTypeElement(Consts.ACTIVITY);
        TypeMirror activityType = activity.asType();

        for (Element element : routeElements) {
            RouteMeta routeMeta;
            TypeMirror tm = element.asType();
            Route route = element.getAnnotation(Route.class);
            if (typesUtils.isSubtype(tm, activityType)) {
                routeMeta = new RouteMeta(RouteType.ACTIVITY, route, element);
            } else {
                throw new IllegalArgumentException("[Just Support Activity/IService Route] :" + element);
            }
            categories(routeMeta);
        }


    }

    private void categories(RouteMeta routeMeta) {
        if (routeVerify(routeMeta)) {
            List<RouteMeta> routeMetas = groupMap.get(routeMeta.getGroup());
            if (Utils.isEmpty(routeMetas)) {
                List<RouteMeta> routeMetaSet = new ArrayList<>();
                routeMetaSet.add(routeMeta);
                groupMap.put(routeMeta.getGroup(), routeMetaSet);
            } else {
                routeMetas.add(routeMeta);
            }
        }
    }

    private boolean routeVerify(RouteMeta meta) {
        String path = meta.getPath();
        String group = meta.getGroup();
        //路由地址必须以 / 开头
        if (Utils.isEmpty(path) || !path.startsWith("/")) {
            return false;
        }
        //如果没有设置分组,以第一个 / 后的节点为分组(所以必须path两个/)
        if (Utils.isEmpty(group)) {
            String defaultGroup = path.substring(1, path.indexOf("/", 1));
            if (Utils.isEmpty(defaultGroup)) {
                return false;
            }
            meta.setGroup(defaultGroup);
            return true;
        }
        return true;
    }
}
